/**
 *  Eclipse Public License 1.0
 */
package org.fireblade.easysms;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLDecoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import android.app.Service;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

/**
 * handle & dispatch the request
 */
public class HttpActionHandler {
  /**
   * own log tag
   */
  private static final String LOGTAG = MainActivity.EASY_SMS + HttpActionHandler.class.getSimpleName();
  private static final String HTTP_200_HEADER = "HTTP/1.1 200 OK\r\nServer: EasySMS\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\n\r\n";
  private static final String HTTP_404_HEADER = "HTTP/1.1 404 NOT FOUND\r\nServer: EasySMS\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\n\r\nSorry, not found :( - try here: <a href=\"/index.html\">Start</a>";
  private static final byte[] FAVICON_HEADER = "HTTP/1.1 200 OK\r\nCache-Control: max-age=10000000, public\r\nConnection: close\r\nContent-Type: image/x-icon\r\nContent-Length: 2238\r\n\r\n"
    .getBytes();
  private static final String STYLE_SHEET = "HTTP/1.1 200 OK\r\nCache-Control: max-age=10000000, public\r\n\r\ntd{font-family:\"Arial\", \"Sans serif\";font-size:85%}\r\nli{font-family:\"Arial\", \"Sans serif\";font-size:75%}\r\nbody { font-family:\"Arial\", \"Sans serif\";font-size:100%; margin:0; padding:0; cursor:default; }\r\n";
  /** connection counter */
  private static int connectionCounter;


  /**
   * handle a client connection
   * @param client the socket
   * @return true if a connection was handled. false if input or output failed
   */
  static boolean handleClient(BufferedInputStream in, OutputStream out, Service service) {
    try {
      Log.d(LOGTAG, "Verbindung " + ++connectionCounter + ": start");
      BufferedReader requestReader = new BufferedReader(new InputStreamReader(in), 256);
      String requestLine = null;
      try {
        requestLine = requestReader.readLine();
      } catch (IOException e) {
        Log.d(LOGTAG, "Connection closed: " + e);
        return false;
      }
      if (null == requestLine) {
        return false;
      }
      // StringBuffer request = new StringBuffer();
      // request.append(requestLine);
      // request.append(Util.NEWLINE);
      String line = null;

      String credentials = "";
      // int len = 0; // len of a post content, not used at the moment as no posts in app
      while ((line = requestReader.readLine()) != null) {
        // request.append(line);
        // request.append(Util.NEWLINE);
        if (line.equals(Util.EMPTY_STRING)) {
          // request finished. must read until this point because of
          // bt connection pcproxy<->phone
          break;
        }
      }
      Log.d(LOGTAG, "Request: " + requestLine /* or just request */);
      // "dispatch"
      Map<String, String> values = parseGetRequest(requestLine);
      if (requestLine.indexOf("/ HTTP") > 0 || requestLine.indexOf("/index.html") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        try {
          writer.write(HTTP_200_HEADER);
          HttpActionIndex.process(service, values, writer);
          writer.flush();
        } catch (RuntimeException e) {
          writer.write("Exception: " + e);
          writer.write(Util.NEWLINE);
          writer.flush();
          StackTraceElement[] el = e.getStackTrace();
          for (int i = 0; i < el.length; i++) {
            writer.write(el[i].toString());
            writer.write(Util.NEWLINE);
            writer.flush();
          }
          throw e;
        } finally {
          writer.flush();
        }

      } else if (requestLine.indexOf("/checkUpdate") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        try {
          writer.write(HTTP_200_HEADER);
          HttpActionCheckUpdate.process(service, values, writer);
          writer.flush();
        } catch (RuntimeException e) {
          writer.write("Exception: " + e);
          writer.write(Util.NEWLINE);
          writer.flush();
          StackTraceElement[] el = e.getStackTrace();
          for (int i = 0; i < el.length; i++) {
            writer.write(el[i].toString());
            writer.write(Util.NEWLINE);
            writer.flush();
          }
          throw e;
        } finally {
          writer.flush();
        }
        
      } else if (requestLine.indexOf("/donate.html") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        writer.write(HTTP_200_HEADER);
        HttpActionDonate.process(service, values, writer);
        writer.flush();

      } else if (requestLine.indexOf("/getpicture?") > 0) {
        BufferedOutputStream bufferedOut = new BufferedOutputStream(out, 4096);
        HttpActionGetPicture.process(service, values, bufferedOut);
        bufferedOut.flush();

      } else if (requestLine.indexOf("/getthreads?") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        try {
          writer.write(HTTP_200_HEADER);
          HttpActionGetThreads.process(service, values, writer);
          writer.flush();
        } catch (RuntimeException e) {
          writer.write("Exception: " + e);
          writer.write(Util.NEWLINE);
          writer.flush();
          StackTraceElement[] el = e.getStackTrace();
          for (int i = 0; i < el.length; i++) {
            writer.write(el[i].toString());
            writer.write(Util.NEWLINE);
            writer.flush();
          }
          throw e;
        } finally {
          writer.flush();
        }

      } else if (requestLine.indexOf("/addressbook?") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        try {
          writer.write(HTTP_200_HEADER);
          HttpActionGetAddressbook.process(service, values, writer);
          writer.flush();
        } catch (RuntimeException e) {
          writer.write("Exception: " + e);
          writer.write(Util.NEWLINE);
          writer.flush();
          StackTraceElement[] el = e.getStackTrace();
          for (int i = 0; i < el.length; i++) {
            writer.write(el[i].toString());
            writer.write(Util.NEWLINE);
            writer.flush();
          }
          throw e;
        } finally {
          writer.flush();
        }

      } else if (requestLine.indexOf("/newmessage?") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        try {
          writer.write(HTTP_200_HEADER);
          HttpActionNewMessage.process(service, values, writer);
          writer.flush();
        } catch (RuntimeException e) {
          writer.write("Exception: " + e);
          writer.write(Util.NEWLINE);
          writer.flush();
          StackTraceElement[] el = e.getStackTrace();
          for (int i = 0; i < el.length; i++) {
            writer.write(el[i].toString());
            writer.write(Util.NEWLINE);
            writer.flush();
          }
          throw e;
        } finally {
          writer.flush();
        }

      } else if (requestLine.indexOf("/showthread?") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        try {
          writer.write(HTTP_200_HEADER);
          HttpActionShowThread.process(service, values, writer);
          writer.flush();
        } catch (RuntimeException e) {
          writer.write("Exception: " + e);
          writer.write(Util.NEWLINE);
          writer.flush();
          StackTraceElement[] el = e.getStackTrace();
          for (int i = 0; i < el.length; i++) {
            writer.write(el[i].toString());
            writer.write(Util.NEWLINE);
            writer.flush();
          }
          throw e;
        } finally {
          writer.flush();
        }

      } else if (requestLine.indexOf("/style.css") > 0) {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 1024);
        writer.write(STYLE_SHEET);
        writer.flush();

      } else if (requestLine.indexOf("favicon.ico") > 0) {
        InputStream pictureIn = service.getResources().openRawResource(R.raw.favicon);
        BufferedOutputStream bufferedOut = new BufferedOutputStream(out, 4096);
        bufferedOut.write(FAVICON_HEADER);
        byte[] buf = new byte[256];
        int count = -1;
        while ((count = pictureIn.read(buf)) != -1) {
          bufferedOut.write(buf, 0, count);
        }
        bufferedOut.flush();
        
      } else {
        BufferedWriter writer = new BufferedLineBreakWriter(new OutputStreamWriter(out), 4096);
        writer.write(HTTP_404_HEADER);
        writer.write("\r\n<br/>");
        writer.write(requestLine + " not available.");
        writer.flush();
      }
      
      Log.d(LOGTAG, "Verbindung " + connectionCounter + ": ende");
    } catch (Exception e) {
      Log.e(LOGTAG, "Error: " + e, e);
    }
    return true;
  }


  /**
   * parse the query part of the get request (part after ?)
   * @param requestLine the request line
   * @return
   */
  static Map<String, String> parseGetRequest(String requestLine) {
    // no ? ?
    if (requestLine.indexOf('?') < 0) {
      return Collections.emptyMap();
    }

    Map<String, String> values = new HashMap<String, String>();
    requestLine = requestLine.substring(requestLine.indexOf("?") + 1);
    requestLine = requestLine.substring(0, requestLine.indexOf("HTTP/1."));
    requestLine = requestLine.trim();

    // nothing useful after a ? ?
    if (requestLine.equals("")) {
      return Collections.emptyMap();
    }

    // parse the query parts separated by &
    StringTokenizer tokenizer = new StringTokenizer(requestLine, "&");
    while (tokenizer.hasMoreElements()) {
      String token = tokenizer.nextToken();
      String key = token.substring(0, token.indexOf("="));
      String value = token.substring(key.length() + 1);
      value = URLDecoder.decode(value).trim();
      if (!value.equals("")) {
        values.put(key, value);
      }
    }
    return values;
  }
}
